using System;
using System.Collections.Generic;
using System.Text;
using SlimDX;
using Barrage.Elements;
using Barrage.Audios;
using Barrage.Global;
using NLog;

namespace Barrage
{
    /// <summary>
    /// Base class for scenes.
    /// A scene holds a list of elements to be updated/renderd, and a camera.
    /// </summary>
    public abstract class Scene:IDisposable
    {
        /// <summary>
        /// The scene currently being rendered/updated
        /// </summary>
        public static Scene CurrentInstance { get { return currentInstance; } set { currentInstance = value; } }
        static Scene currentInstance = null;

        /// <summary>
        /// The camera used to render the scene elements
        /// </summary>
        public Camera Camera { get { return camera; } set { camera = value; } }
        
        /// <summary>
        /// Lights that will be used on the items rendered without lighting information
        /// </summary>
        public List<Light> DefaultLights { get { return defaultLights; } }
        /// <summary>
        /// Lights that will be used on the items rendered without lighting information
        /// </summary>
        protected List<Light> defaultLights = new List<Light>(3);

        Camera camera = null;
        List<Element> elements = new List<Element>();

        /// <summary>
        /// Adds a light to the default light list
        /// </summary>
        /// <param name="l">Light to be added</param>
        public void addLight(Light l)
        {
            defaultLights.Add(l);
        }

        /// <summary>
        /// Renders every element in the scene
        /// </summary>
        public void Render()
        {
            long initTime = Timer.DefaultTimer.CurrentTotalTime;
            foreach (Element e in elements)
            {
                e.Render();
            }

            LogManager.GetLogger(ToString()).Debug(ToString() + " Rendered in " + (Timer.DefaultTimer.CurrentTotalTime - initTime) + " ms");
        }

        /// <summary>
        /// Updates every element in the scene
        /// </summary>
        public virtual void Update()
        {
            long initTime = Timer.DefaultTimer.CurrentTotalTime;
            foreach (Element e in elements)
            {
                e.Update();
            }
            LogManager.GetLogger(ToString()).Debug(ToString() + " Updated in " + (Timer.DefaultTimer.CurrentTotalTime - initTime) + " ms");
        }

        /// <summary>
        /// Adds an element to the scene element list
        /// </summary>
        /// <param name="e">Element to be added</param>
        public virtual void Add(Element e)
        {
            elements.Add(e);
        }

        /// <summary>
        /// Clear resources and pointers to other objects
        /// </summary>
        public virtual void Dispose()
        {
            camera = null;
            elements.Clear();
            elements = null;
            defaultLights.Clear();
            defaultLights = null;
            if (currentInstance == this) currentInstance = null;
            NLog.LogManager.GetLogger(ToString()).Debug("Disposing"); 
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Destructor. Clear resources
        /// </summary>
        ~Scene()
        {
            Dispose();
        }
    }
}
